package com.zx.flow.core.execute.eventhandler;

import com.zx.flow.api.config.FlowConfig;
import com.zx.flow.api.config.FlowConfigNode;
import com.zx.flow.api.dict.FlowDict.Event;
import com.zx.flow.api.dict.FlowDict.OperationType;
import com.zx.flow.api.execute.model.FlowContext;
import com.zx.flow.api.execute.model.FlowNode;
import com.zx.flow.api.execute.request.FlowParamAction;
import com.zx.flow.api.execute.request.FlowParamEnd;
import com.zx.flow.api.execute.request.FlowParamNodeEntry;
import com.zx.flow.api.execute.request.FlowParamNodeFinish;
import com.zx.flow.api.execute.response.FlowResult;
import com.zx.flow.api.util.AssertUtil;
import com.zx.flow.api.util.OperatorsUtil;
import com.zx.flow.core.execute.EventHandler;
import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;

/**
 * 事件处理器【流程->同意&驳回】
 */
public class EventFlowActionHandler extends EventHandler<FlowParamAction> {

    @Override
    public boolean in(FlowContext flow, FlowParamAction param) {
        AssertUtil.checkOperator(flow, param.getNodeId(), param.getAccountCode());
        return flow != null && (
                Objects.equals(param.getEvent(), Event.nodeApproved.getCode())
                        || Objects.equals(param.getEvent(), Event.nodeRejection.getCode())
        );
    }

    @Override
    public FlowResult on(FlowContext flow, FlowParamAction param) {
        // 当前code
        String nodeCode = flow.getCurrentNodeCode();

        FlowConfig config = this.getFlowConfig(flow.getFlowConfigCode(), flow.getFlowConfigId());
        FlowNode currentNode = this.getNode(param.getId(), param.getNodeId());
        FlowConfigNode currentNodeConfig = config.getNode(currentNode.getNodeCurrentCode());
        // 下一个节点配置。toNodeConfig 可能为null
        FlowConfigNode toNodeConfig = config.getToConfig(nodeCode, Event.getByCode(param.getEvent()),
                flow.getExtendData());
        String toNodeCode = toNodeConfig == null ? null : toNodeConfig.getCode();
        // 完成当前节点
        flow = this.execute(new FlowParamNodeFinish(flow.getId(), currentNode.getId(), toNodeCode,
                Event.getByCode(param.getEvent()),
                param.getRemark(), param.getAccountCode())).getFlowContext();

        // 如果 OperationType=all, 必须所有操作人approved，才能继续执行。
        if (Objects.equals(param.getEvent(), Event.nodeApproved.getCode())
                && Objects.equals(currentNodeConfig.getOperatorType(), OperationType.all.getCode())
                // 所有人都是否全部通过
                && !OperatorsUtil.isAllOperator(flow.getNodes(), nodeCode)
        ) {
            // 开始新节点[还是本节点],设置操作人：因为可能当前节点的操作人经过删除、增加、转办等操作，不允许再次获得重新获得操作人
            flow = this.execute(new FlowParamNodeEntry(flow.getId(), nodeCode, currentNode.getOperators()))
                    .getFlowContext();
            return FlowResult.ok(flow);
        }

        // 触发监听[两种事件]
        this.listener(currentNode, Event.nodeAction);
        this.listener(currentNode, Event.getByCode(param.getEvent()));

        // 1.当前节点是结束节点
        if (config.isEnd(currentNodeConfig.getCode())) {
            // 什么都不用做
            return FlowResult.ok(flow);
        }

        if (config.isStart(toNodeCode)) {
            // 下一个节点是开始节点【被驳回】,添加申请人为操作人
            flow = this.execute(new FlowParamNodeEntry(flow.getId(), toNodeCode,
                    Arrays.asList(OperatorsUtil.getApply(flow)))).getFlowContext();
        } else if (config.isEnd(toNodeCode)) {
            // 下一个节点是结束节点
            flow = this.execute(new FlowParamEnd(param.getId())).getFlowContext();
            return FlowResult.ok(flow);
        } else {
            flow = this.execute(new FlowParamNodeEntry(flow.getId(), toNodeCode, Collections.emptyList()))
                    .getFlowContext();
        }
        return FlowResult.ok(flow);
    }

}
